#include "student.h"
int insert(char * id,char * name,int grade)
{
	char inte[20];
	int result=0;
 	int fd=open(filename,O_CREAT|O_RDWR,0644);	//文件主以读写方式打开文件
	//printf("fd is %d\n",fd);
	result=lseek(fd,0,SEEK_END);	//移动指针到文件末尾
	sprintf(inte,"%-10d",1);
	result=write(fd,inte,10);//写入数据有效性
	sprintf(inte,"%-20s",id);
	result=write(fd,inte,20);	//写入学号
	sprintf(inte,"%-20s",name);
	result=write(fd,inte,20);	//写入姓名
	sprintf(inte,"%-10d",grade);
	result=write(fd,inte,10);	//写入成绩
	result=write(fd,"\n",1);
	result=close(fd);	//关闭文件
	return result;
}
//获取数据库文件大小
int getFileSize()
{
	struct stat buf;
	stat(filename,&buf);
	return buf.st_size/60;
}
//去除尾部空格
void trim(char * str)
{
	for(int i=0;i<20;i++)
	{
		if(str[i]==' ')
		{
			str[i]='\0';
			break;
		}
	}
}
//获取学号的偏移
int getOffSet(char * id)
{
	int num=getFileSize();	//获取数据总量
	int offSet=0;//初始化偏移量为0
	char buf[20];
	int fd=open(filename,O_RDONLY);//以只读方式打开文件
	for(int i=0;i<num;i++)
	{
		read(fd,buf,10);	//读取数据有效性
		trim(buf);
		if(atoi(buf)!=1)	//如果数据无效
		{
			i--;	//回退一格
			num--;//总量减一
			lseek(fd,51,SEEK_CUR);//指针后移
			offSet+=61;//偏移量增加
			continue;//进行下一次循环
		}
		read(fd,buf,20);	//读取学号
		trim(buf);
		if(strcmp(id,buf)==0)	//如果找到了要找的学号
		{
			close(fd);//关闭文件
			return offSet;//返回偏移量
		}
		else	//否则
		{
			lseek(fd,31,SEEK_CUR);//指针后移
			offSet+=61;//增加偏移量
		}
	}
	return -1;	//表明没有找到
}
Student query(char * id)
{
	int offSet=getOffSet(id);//获取偏移量
	Student student={"0","null",0,0};//声明Student变量并赋值为无效数据
	char buf[10];
	if(offSet==-1)	//如果没有该数据
		return student;//返回一条无效数据
	int fd=open(filename,O_RDONLY);//以只读方式打开文件
	lseek(fd,offSet,SEEK_SET);//偏移文件
	read(fd,buf,10);	//读取有效性
	trim(buf);
	student.valid=atoi(buf);
	read(fd,student.id,20);//读取学号
	trim(student.id);
	read(fd,student.name,20);//读取姓名
	trim(student.name);
	read(fd,buf,10);//读取成绩
	trim(buf);
	student.grade=atoi(buf);
	close(fd);//关闭文件
	return student;
}
Student * queryAll()
{
	int num=getFileSize();	//获取数据总量
	Student * stuP=(Student *)malloc(sizeof(Student)*(num+1));//申请数组空间 
	int fd,i;
	char buf[10];
	fd=open(filename,O_RDONLY);	//以只读方式打开文件
	for(i=0;i<num;i++)
	{
		read(fd,buf,10);	//读取数据有效性
		trim(buf);
		stuP[i].valid=atoi(buf);//转换成整型并赋值
		if(stuP[i].valid!=1)	//如果数据无效
		{
			i--;	//回退一格
			num--;//总量减一
			lseek(fd,51,SEEK_CUR);//移动指针
			continue;//进行下一次循环
		}
		read(fd,stuP[i].id,20);	//读取学号
		trim(stuP[i].id);
		read(fd,stuP[i].name,20);//读取姓名
		trim(stuP[i].name);
		read(fd,buf,10);//读取成绩
		trim(buf);
		stuP[i].grade=atoi(buf);
		read(fd,buf,1);//读取换行符
	}
	stuP[i].valid=0;
	num=i;
	//printf("num is %d\n",num);
	//升序排序
	for(i=0;i<num;i++)
		for(int j=0;j<i;j++)
		{
			if(strcmp(stuP[j].id,stuP[j+1].id)>0)
			{
				Student temp=stuP[j];
				stuP[j]=stuP[j+1];
				stuP[j+1]=temp;
			}
		}
	//printf("%s %d",stuP[0].id,stuP[0].valid);
	//printf("地址为%p",stuP);
	return stuP;
}
int delete(char * id)
{
	int fd=open(filename,O_WRONLY);//以写方式打开文件
	int offSet=getOffSet(id);//获取偏移量
	if(offSet==-1)//如果没有找到
		return -1;//返回失败
	lseek(fd,offSet,SEEK_SET);//偏移到对应的位置
	char buf[10];
	sprintf(buf,"%-10d",0);//写入无效对应的值
	write(fd,buf,10);//写入0
	return 0;//表明成功
}
void compress()
{
	Student *students=queryAll();//查询出所有记录
	int fd=open(filename,O_WRONLY|O_TRUNC,0644);//以覆盖方式打开文件
	char inte[20];
	for(int i=0;students[i].valid!=0;i++)	//遍历所有记录
	{
		//写入记录
	char inte[20];
	sprintf(inte,"%-10d",1);
	write(fd,inte,10);//写入数据有效性
	sprintf(inte,"%-20s",students[i].id);
	write(fd,inte,20);	//写入学号
	sprintf(inte,"%-20s",students[i].name);
	write(fd,inte,20);	//写入姓名
	sprintf(inte,"%-10d",students[i].grade);
	write(fd,inte,10);	//写入成绩
	write(fd,"\n",1);
	}
	puts("压缩成功！");
	close(fd);//关闭文件
}
int main()
{
	int flag=1,cho;
	char id[20],name[20];
	int grade;
	Student *st;
	Student s;
	while(flag)
	{
		puts("1.追加一条记录\n2.根据学号读出一条记录\n3.按学号升序列出所有记录\n4.按学号删除一条记录\n5.压缩掉被删除的记录\n6.退出\n请选择：");
		scanf("%d",&cho);
		switch(cho)
		{
			case 1:
				printf("请输入学号:");scanf("%s",id);
				printf("请输入姓名:");scanf("%s",name);
				printf("请输入成绩:");scanf("%d",&grade);
				insert(id,name,grade);
			break;
			case 2:
				printf("请输入学号:");scanf("%s",id);
				s=query(id);
				if(s.valid==0)
					printf("该记录不存在！\n");
				else
				printf("学号:%s,姓名:%s,成绩:%d\n",s.id,s.name,s.grade);
			break;
			case 3:
				st=queryAll();
				for(int i=0;st[i].valid!=0;i++)
				{
					printf("学号:%s,姓名:%s,成绩%d\n",st[i].id,st[i].name,st[i].grade);
				}
			break;
			case 4:
				printf("请输入要删除的学号:");scanf("%s",id);
				printf("记录%s\n",delete(id)?"删除失败":"成功删除");
			break;
			case 5:
				compress();
			break;
			case 6:
				flag=0;
			break;
		}
	}
	return 0;
}
